using Engine;
using Game;
using GameEntitySystem;

namespace SCIENEW {
    public class EntityDeviceBehavior<T> : DeviceBehavior where T : Component {
        protected SubsystemBlockEntities m_subsystemBlockEntities;
        protected SubsystemAudio m_subsystemAudio;

        public EntityDeviceBehavior(Project project) : base(project) {
            m_subsystemAudio = project.FindSubsystem<SubsystemAudio>(true);
            m_subsystemBlockEntities = project.FindSubsystem<SubsystemBlockEntities>(true);
        }

        public override void OnBlockAdded(int value, int oldValue, int x, int y, int z) {
            DeviceBlock deviceBlock = DevicesBlockManager.GetDevice(value); //获取方块值所对应的设备实例
            if (deviceBlock is IEntityDevice<T> entityDevice) {
                //设备是实体方块
                string entityName = entityDevice.GetEntityName(value);
                DeviceEntityUtils.CreateDeviceEntity(Project.FindSubsystem<SubsystemTerrain>(true), entityName, new Point3(x, y, z));
            }
        }

        public override void OnBlockRemoved(int value, int newValue, int x, int y, int z) {
            DeviceEntityUtils.RemoveDeviceEntity(Project.FindSubsystem<SubsystemTerrain>(true), new Point3(x, y, z));
        }

        public override void OnBlockModified(int value, int oldValue, int x, int y, int z) {
            DeviceBlock oldDeviceBlock = DevicesBlockManager.GetDevice(oldValue); //获取方块值所对应的设备实例
            DeviceBlock newDeviceBlock = DevicesBlockManager.GetDevice(value); //获取方块值所对应的设备实例
            if (oldDeviceBlock.GetCraftingId() != newDeviceBlock.GetCraftingId()) {//特殊值变化后前后两个方块是不一样的方块
                DeviceEntityUtils.RemoveDeviceEntity(Project.FindSubsystem<SubsystemTerrain>(true), new Point3(x, y, z));
                if (newDeviceBlock is IEntityDevice<T> newEntityDevice) {
                    //设备是实体方块
                    string entityName = newEntityDevice.GetEntityName(value);
                    DeviceEntityUtils.CreateDeviceEntity(Project.FindSubsystem<SubsystemTerrain>(true), entityName, new Point3(x, y, z));
                }
            }
        }

        public override bool OnInteract(TerrainRaycastResult raycastResult, ComponentMiner componentMiner) {
            DeviceBlock deviceBlock = DevicesBlockManager.GetDevice(raycastResult.Value); //获取方块值所对应的设备实例
            if (deviceBlock is IEntityDevice<T> entityDevice) {
                if (DeviceEntityUtils.GetDeviceEntity(Project.FindSubsystem<SubsystemTerrain>(true), raycastResult.CellFace.Point, out ComponentBlockEntity blockEntity)
                    && componentMiner.ComponentPlayer != null) {
                    T component = blockEntity.Entity.FindComponent<T>(throwOnError: true);
                    componentMiner.ComponentPlayer.ComponentGui.ModalPanelWidget = entityDevice.GetWidget(componentMiner.Inventory, component);
                    AudioManager.PlaySound("Audio/UI/ButtonClick", 1f, 0f, 0f);
                    return true;
                }
            }
            return false;
        }

        public override void OnHitByProjectile(CellFace cellFace, WorldItem worldItem) {
            if (worldItem.ToRemove) {
                return;
            }
            ComponentBlockEntity blockEntity = m_subsystemBlockEntities.GetBlockEntity(cellFace.X, cellFace.Y, cellFace.Z);
            if (blockEntity != null) {
                IInventory inventory = blockEntity.Entity.FindComponent<IInventory>(throwOnError: false);
                if (inventory == null) return;
                var pickable = worldItem as Pickable;
                var value = worldItem.Value;
                int pickableCount = pickable?.Count ?? 1;
                if (inventory is IElectricElementCrafterComponent crafterComponent && crafterComponent.RequireItemSlotIndex.HasValue) {//需要添加至指定格子
                    int slotIndex = crafterComponent.RequireItemSlotIndex.Value;
                    int count2 = MathUtils.Min(pickableCount, inventory.GetSlotCapacity(slotIndex, value) - inventory.GetSlotCount(slotIndex));
                    if (inventory.GetSlotCount(slotIndex) != 0 && inventory.GetSlotValue(slotIndex) != value)
                        return;
                    inventory.AddSlotItems(slotIndex, value, count2);
                    if (count2 > 0)
                        m_subsystemAudio.PlaySound("Audio/PickableCollected", 1f, 0f, worldItem.Position, 3f, true);
                    if (pickableCount <= count2)
                        worldItem.ToRemove = true;
                    else if (pickable != null)
                        pickable.Count = pickableCount - count2;
                    return;
                }

                int remainCount = ComponentInventoryBase.AcquireItems(inventory, worldItem.Value, pickableCount);
                if (remainCount < pickableCount) {
                    m_subsystemAudio.PlaySound(
                        "Audio/PickableCollected",
                        1f,
                        0f,
                        worldItem.Position,
                        3f,
                        autoDelay: true
                    );
                }
                if (remainCount <= 0) {
                    worldItem.ToRemove = true;
                }
                else if (pickable != null) {
                    pickable.Count = remainCount;
                }
            }
        }
    }
}